
#include <BPainter>
#include <BCursor>
#include <BFont>
#include <BMouseEvent>
#include <BChangeEvent>
#include <BKeyEvent>
#include <BScrollBar>

#include <BTreeWidget>
#include "member_BTreeWidget.h"
#include "member_BTreeItem.h"
#include "member_BWidget.h"

using namespace BWE;

#define member					(*(member_BTreeWidget*)_ptr)
#define member_allocate()		_ptr = new member_BTreeWidget(this)
#define member_release()		delete (member_BTreeWidget*)_ptr

BTreeWidget::BTreeWidget(BWidget* parent) : BScrollArea(parent)
{
	member_allocate();
}
BTreeWidget::~BTreeWidget()
{
	member_release();
}

void BTreeWidget::expandAll()
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		member.expandAll(topItem);
	}
}
void BTreeWidget::shrinkAll()
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		member.shrinkAll(topItem);
	}
}

void BTreeWidget::setIndent(int indent)
{
	if(member.indent != indent)
	{
		member.indent = indent;
	}
}
int BTreeWidget::indent() const
{
	return member.indent;
}

void BTreeWidget::setSpace(int space)
{
	if (member.space != space)
	{
		member.space = space;
		this->fresh();
	}
}
int BTreeWidget::space() const
{
	return member.space;
}

void BTreeWidget::setArrowSize(int arrowSize)
{
	if (member.arrowSize != arrowSize)
	{
		member.arrowSize = arrowSize;
		this->fresh();
	}
}
int BTreeWidget::arrowSize() const
{
	return member.arrowSize;
}

bool BTreeWidget::addTopItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->tree == this)
		return true;
	if (item_member(item)->tree)
		item_member(item)->tree->removeItem(item);
	member.topItems.append(item);
	if (item_member(item)->parent)
		item_member(item)->parent->removeChild(item);
	item_member(item)->attach(this);
	member.dirty = true;
	this->fresh();
	return true;
}
BTreeItem* BTreeWidget::addTopItem(const BString& text)
{
	BTreeItemHolder item = new BTreeItem(text);
	if (addTopItem(item))
		return item;
	return 0;
}
bool BTreeWidget::removeTopItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->tree != this)
		return false;
	if (item_member(item)->parent)
		return false;
	member.selectedItems.remove(item);
	member.topItems.remove(item);
	member.dirty = true;
	this->fresh();
	return true;
}
bool BTreeWidget::removeItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (item_member(item)->tree != this)
		return false;
	member.selectedItems.remove(item);
	if (item_member(item)->parent)
	{
		item->setParent(0);
		member.dirty = true;
		this->fresh();
		return true;
	}
	return removeTopItem(item);
}
void BTreeWidget::clearItems()
{
	if (member.topItems.size())
	{
		member.topItems.clear();
		member.visualItems.clear();
		member.selectedItems.clear();
		this->fresh();
	}
}

int BTreeWidget::topItemCount() const
{
	return member.topItems.size();
}
BTreeItem* BTreeWidget::topItem(int index)
{
	return member.topItems(index);
}
const BTreeItem* BTreeWidget::topItem(int index) const
{
	return member.topItems(index);
}

BTreeItem* BTreeWidget::topItem(const BString& text)
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		if (topItem->text() == text)
			return topItem;
	}
	return 0;
}
const BTreeItem* BTreeWidget::topItem(const BString& text) const
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		const BTreeItem* topItem = member.topItems[i];
		if (topItem->text() == text)
			return topItem;
	}
	return 0;
}

BTreeItem* BTreeWidget::itemAt(const BPoint& point)
{
	BRect rect = this->clientRect();
	if(!rect.contain(point))
		return 0;
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		BTreeItem* item = member.visualItems[i];
		if (item_member(item)->rect.contain(point))
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::itemAt(const BPoint& point) const
{
	BRect rect = this->clientRect();
	if (!rect.contain(point))
		return 0;
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		BRect rect = item->rect();
		if (rect.contain(point))
			return item;
	}
	return 0;
}

BTreeItem* BTreeWidget::item(const BString& text)
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		BTreeItem* item = topItem->find(text);
		if (item)
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::item(const BString& text) const
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		BTreeItem* item = topItem->find(text);
		if (item)
			return item;
	}
	return 0;
}

BTreeItem* BTreeWidget::item(const BValue& value)
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		BTreeItem* item = topItem->find(value);
		if (item)
			return item;
	}
	return 0;
}
const BTreeItem* BTreeWidget::item(const BValue& value) const
{
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		BTreeItem* item = topItem->find(value);
		if (item)
			return item;
	}
	return 0;
}

void BTreeWidget::setRowHeight(int rowHeight)
{
	if(member.rowHeight != rowHeight)
	{
		member.rowHeight = rowHeight;
		BScrollBar* vscrollBar = this->verticalScrollBar();
		if (vscrollBar)
		{
			vscrollBar->setStep(rowHeight);
		}
		this->fresh();
	}
}
int BTreeWidget::rowHeight() const
{
	return member.rowHeight;
}

void BTreeWidget::setImageSize(const BSize& imageSize)
{
	if(member.imageSize != imageSize)
	{
		member.imageSize = imageSize;
		this->fresh();
	}
}
const BSize& BTreeWidget::imageSize() const
{
	return member.imageSize;
}

int BTreeWidget::selectedItemCount() const
{
	return member.selectedItems.size();
}
BTreeItem* BTreeWidget::selectedItem(int index)
{
	return member.selectedItems(index);
}
const BTreeItem* BTreeWidget::selectedItem(int index) const
{
	return member.selectedItems(index);
}

bool BTreeWidget::setItemSelected(BTreeItem* item, bool selected)
{
	if (!item)
		return false;
	if (!member.multiChoose)
	{
		clearSelection();
	}
	if (selected)
	{
		if (!member.selectedItems.contain(item))
		{
			member.selectedItems.append(item);
			item_member(item)->selected = true;
			emit(Signal_ItemSelected, item);
		}
	}
	else
	{
		if (member.selectedItems.remove(item))
		{
			item_member(item)->selected = false;
			emit(Signal_ItemUnSelected, item);
		}
	}
	return true;
}
void BTreeWidget::clearSelection()
{
	for(int i = 0; i < member.selectedItems.size(); i++)
	{
		BTreeItem* item = member.selectedItems[i];
		item_member(item)->selected = false;
	}
	member.selectedItems.clear();
}

bool BTreeWidget::contains(const BTreeItem* item)
{
	if (!item)
		return false;
	for (int i = 0; i < member.topItems.size(); i++)
	{
		BTreeItem* topItem = member.topItems[i];
		if (topItem->containItem(item))
			return true;
	}
	return false;
}

void BTreeWidget::scrollArea()
{
	BRect area = this->area();
	member.dirty = true;
	this->fresh();
}

void BTreeWidget::styleEvent(const BEvent& event)
{
	const BFont* font = this->font();
	if (font)
	{
		if (member.rowHeight < font->height())
			setRowHeight(font->height());
	}
}
void BTreeWidget::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	member.dirty = true;
	this->fresh();
}

void BTreeWidget::freshEvent(const BEvent& event)
{
	if (member.dirty)
	{
		member.dirty = false;
		member.freshRects();
	}
}
void BTreeWidget::paintEvent(const BEvent& event)
{
	const BRect& crect = this->clientRect();
	const BRect& area = this->area();
	const BPoint& offset = this->offset();

	BPainter painter(this);
	painter.drawBackground();
	painter.drawContent();
	painter.drawPerch();

	BSize size = this->size();
	painter.setClip(crect);
	for (int i = 0; i < member.visualItems.size(); i++)
	{
		const BTreeItem* item = member.visualItems[i];
		BRect rect = item->rect();

		StyleRole colorRole = Style_None;
		if(item->isSelected())
		{
			colorRole = Color_Item_Selected;
		}
		else if(member.hoveredItem == item)
		{
			colorRole = Color_Item_Hovered;
		}
		if (colorRole && painter.setColor(colorRole))
		{
			painter.fillRect(rect);
			painter.drawRect(rect);
		}

		if(item->childCount())
		{
			BRect arrow_rect = item_member(item)->arrowRect.align(Align_Center, BSize(member.arrowSize));

			if(member.hoveredItem == item && member.hoveredIndicator)
				painter.setColor(Color_Arrow_Hovered);
			else
				painter.setColor(Color_Arrow);
			if (item->isExpanded())
			{
				if (member.expandImage)
					painter.drawImage(arrow_rect, member.expandImage);
				else
					painter.fillTriangle(member.expandA + arrow_rect.pos(), member.expandB + arrow_rect.pos(), member.expandC + arrow_rect.pos());
			}
			else
			{
				if (member.shrinkImage)
					painter.drawImage(arrow_rect, member.shrinkImage);
				else
					painter.fillTriangle(member.shrinkA + arrow_rect.pos(), member.shrinkB + arrow_rect.pos(), member.shrinkC + arrow_rect.pos());
			}

		}

		item_member(item)->paint(painter);
	}
	painter.setClip(0, 0, this->width(), this->height());

	painter.drawMargin();
	painter.drawBorder();
}

void BTreeWidget::keyDownEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	if(key == ::Key_LCtrl)
	{
		member.multiChoose = true;
	}
	if(key == ::Key_LShift)
	{
		member.continuChoose = true;
	}
}
void BTreeWidget::keyUpEvent(const BKeyEvent& keyEvent)
{
	Key key = keyEvent.key();
	if(key == ::Key_LCtrl)
	{
		member.multiChoose = false;
	}
	if(key == ::Key_LShift)
	{
		member.continuChoose = false;
	}
}

void BTreeWidget::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.hoveredItem = 0;
	fresh();
}
void BTreeWidget::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	member.hoveredItem = 0;
	fresh();
}

void BTreeWidget::mousePressEvent(const BMouseEvent& mouseEvent)
{
	member.pressPos = mouseEvent.pos();
	if(member.hoveredIndicator)
	{
		member.hoveredItem->expandOrShrink();
		if (member.hoveredItem->childCount() > 0)
		{
			this->fresh();
		}
	}
}
void BTreeWidget::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	Button button = mouseEvent.button();
	BPoint pos = mouseEvent.pos();
}
void BTreeWidget::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BTreeItem* hoveredItem = this->itemAt(pos);
	if(member.hoveredItem != hoveredItem)
	{
		member.hoveredItem = hoveredItem;
		fresh();
	}
	if(hoveredItem)
	{
		bool hoveredIndicator = item_member(hoveredItem)->arrowRect.contain(pos);
		if(member.hoveredIndicator != hoveredIndicator)
		{
			member.hoveredIndicator = hoveredIndicator;
			fresh();
		}
	}
	else
	{
		if(member.hoveredIndicator)
		{
			member.hoveredIndicator = false;
			fresh();
		}
	}
}

void BTreeWidget::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if(!member.hoveredIndicator)
	{
		BTreeItem* item = member.hoveredItem;
		if(item)
		{
			setItemSelected(item, true);
		}
		else
		{
			clearSelection();
		}
		if (mouseEvent.button() == Button_Left)
		{
			emit(Signal_ItemClicked, member.hoveredItem);
		}
	}
	if(mouseEvent.button() == Button_Right)
	{
		emit(Signal_RightClicked, mouseEvent.pos());
	}
	fresh();
}
void BTreeWidget::mouseDoubleClickEvent(const BMouseEvent& mouseEvent)
{
	if(mouseEvent.button() == Button_Left && member.hoveredItem)
	{
		BTreeItem* item = member.hoveredItem;
		emit(Signal_ItemDoubleClicked, item);
		this->fresh();
	}
}
